/**
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-01-24 19:28:34
 * @Description  : 存储源模型验证中间件
 */

const Joi = require('joi')
const { Op } = require('sequelize')
const R = require('@/models/Response')
const { Source } = require('@/models/model')
const { ERROR_USER_CODE, ERROR_SYSTEM_CODE } = require('@/constants/errorCode')
const {
  IS_INTEGER,
  IS_UNSAFE_INTEGER,
  IS_UNSAFE_INTEGER_2
} = require('@/constants/joiSchema')
const { StorageOrigin } = require('@/framework/mongoose')
const { linkTest, linkToLocal, linkToOss } = require('@/utils/storage')
const { LOCAL_STORAGE, OSS_STORAGE } = require('@/constants/storage')

const storageOriginSchema = {
  storageOriginIds: Joi.array().items(Joi.string()),
  storageOriginId: Joi.string(),
  page: IS_INTEGER.min(1).default(1),
  pageSize: IS_INTEGER.min(1).default(999),
  name: Joi.string().min(1).max(50),
  type: IS_INTEGER.valid('LOCAL', 'OSS'),
  isDefault: IS_INTEGER.valid(0, 1),
  sizeMax: IS_UNSAFE_INTEGER_2.min(0),
  path: Joi.string(),
  // .pattern(/^[a-zA-Z0-9_-]+\\(?:[a-zA-Z0-9_-]+\\)*$/),
  accessKey: Joi.string().when('type', {
    is: Joi.valid('OSS'),
    then: Joi.required()
  })
}

const dumpCheck = {
  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证存储源ID的合法性
   * @param {array<string>} storageOriginIds 存储源ID数组
   */
  checkStorageOriginIds: async (storageOriginIds, ingoreDefault = false) => {
    let newstorageOriginIds = [...new Set(storageOriginIds)]
    // 不能出现重复的
    if (newstorageOriginIds.length !== storageOriginIds.length) {
      return false
    }

    if (newstorageOriginIds.length === 0) {
      return true
    }

    // 查看不重复的和数据库的是否对的上
    const myWhere = {
      _id: { $in: newstorageOriginIds }
    }

    // 是否忽略默认存储源
    if (!ingoreDefault) {
      myWhere.isDefault = 0
    }
    const storageOrigins = await StorageOrigin.find(myWhere)
    if (storageOrigins.length !== newstorageOriginIds.length) {
      return false
    }

    return true
  },

  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证存储源名称是否重复
   * @param {string} storageOriginName 存储源名称
   */
  checkStorageOriginName: async (storageOriginName) => {
    const storageOrigin = await StorageOrigin.findOne({
      name: storageOriginName
    })
    if (storageOrigin) {
      return false
    }
    return true
  },

  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 尝试连接到存储源
   */
  checkLinkToStorage: async (type, ctx) => {
    const { path, accessKey, accessSecret, bucketName, endPoint } =
      ctx.request.body
    if (type === LOCAL_STORAGE) {
      return await linkToLocal(path)
    } else if (type === OSS_STORAGE) {
      return await linkToOss(endPoint, accessKey, accessSecret, bucketName)
    }
  }
}

/**
 * @description 存储源列表查询的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listStorageOriginValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: storageOriginSchema.page,
    pageSize: storageOriginSchema.pageSize
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }
  ctx.query = schema.value
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 创建和更新存储源时的验证
 * @param {*} ctx koa上下文
 * @param {*} storageOriginId 存储源ID
 * @param {*} storageOriginName 存储源名称
 */
const addAndUpdCheck = async (
  ctx,
  storageOriginId = null,
  storageOriginName = null
) => {
  // 验证storageOriginId的合法性
  if (storageOriginId !== null) {
    const b4 = await dumpCheck.checkStorageOriginIds([storageOriginId], true)
    if (!b4) {
      ctx.body = R.error(ERROR_USER_CODE.STORAGE_ORIGIN_ID_ERROR)
      return false
    }
  }

  // 验证存储源名称的合法性
  if (storageOriginName !== null && !storageOriginId) {
    const b3 = await dumpCheck.checkStorageOriginName(storageOriginName)
    if (!b3) {
      ctx.body = R.error(ERROR_USER_CODE.STORAGE_ORIGIN_NAME_ERROR)
      return false
    }
  }

  return true
}

/**
 * @description 创建存储源时的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.createStorageOriginValidate = async (ctx, next) => {
  const schema = Joi.object({
    name: storageOriginSchema.name.required(),
    path: storageOriginSchema.path.required(),
    type: storageOriginSchema.type.required(),
    sizeMax: storageOriginSchema.sizeMax.required(),
    isDefault: storageOriginSchema.isDefault.required(),
    accessKey: storageOriginSchema.accessKey,
    accessSecret: storageOriginSchema.accessKey,
    endPoint: storageOriginSchema.accessKey,
    bucketName: storageOriginSchema.accessKey
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { name, type } = ctx.request.body

  // 验证存储源名称的合法性
  const b = await addAndUpdCheck(ctx, null, name)
  if (!b) {
    return
  }

  // 验证存储源是否可以正常连接
  const b4 = await dumpCheck.checkLinkToStorage(type, ctx)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.STORAGE_ORIGIN_LINK_ERROR)
    return
  }

  // 到这里说明参数没有问题,协作存储源情况[0],[-1],[xxx,xxx]
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新存储源时的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.updateStorageOriginValidate = async (ctx, next) => {
  const schema = Joi.object({
    storageOriginId: storageOriginSchema.storageOriginId.required(),
    name: storageOriginSchema.name.required(),
    path: storageOriginSchema.path.required(),
    type: storageOriginSchema.type.required(),
    sizeMax: storageOriginSchema.sizeMax.required(),
    isDefault: storageOriginSchema.isDefault.required(),
    accessKey: storageOriginSchema.accessKey,
    accessSecret: storageOriginSchema.accessKey,
    endPoint: storageOriginSchema.accessKey,
    bucketName: storageOriginSchema.accessKey
  }).validate(ctx.request.body)

  if (schema.error) {
    console.log(schema.error)
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { storageOriginId, name, accessSecret } = ctx.request.body

  const b = await addAndUpdCheck(ctx, storageOriginId, name)
  if (!b) {
    return
  }

  // 验证存储源是否可以正常连接
  const so =
    await StorageOrigin.findById(storageOriginId).select('type accessSecret')

  if (so.type !== LOCAL_STORAGE) {
    if (so.accessSecret.replace(/./g, '*') === accessSecret) {
      ctx.request.body.accessSecret = so.accessKey
    }
  }

  const b4 = await dumpCheck.checkLinkToStorage(so.type, ctx)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.STORAGE_ORIGIN_LINK_ERROR)
    return
  }
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除存储源接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.delStorageOriginsValidate = async (ctx, next) => {
  const schema = Joi.object({
    storageOriginIds: storageOriginSchema.storageOriginIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    console.log(schema.error)
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { storageOriginIds } = ctx.request.body

  // 验证存储源ID数组的合法性
  const b4 = await dumpCheck.checkStorageOriginIds(storageOriginIds)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.STORAGE_ORIGIN_ID_ERROR)
    return
  }
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除存储源接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.setDefaultValidate = async (ctx, next) => {
  const schema = Joi.object({
    storageOriginId: storageOriginSchema.storageOriginId.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { storageOriginId } = ctx.request.body

  // 验证存储源ID数组的合法性,必须存在且default字段为0
  const b4 = await dumpCheck.checkStorageOriginIds([storageOriginId])
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.STORAGE_ORIGIN_ID_ERROR)
    return
  }
  await next()
}
